Skip to content

Feat(Bid) : 선착순 시스템 부하 분산 구현 #119

Merged
yoo20370 merged 14 commits intodevfrom
feat/bid-redis-stock
Dec 24, 2025
Merged

Feat(Bid) : 선착순 시스템 부하 분산 구현 #119
yoo20370 merged 14 commits intodevfrom
feat/bid-redis-stock

Conversation

@yoo20370
Copy link
Contributor

요약

  • RedisLuaScript를 이용하여 부하 분산 구현
  • 요청이 들어오면 우선 레디스에서 원자적으로 재고를 확인하고 재고를 감소하는 로직이 실행된다.
  • 정상적으로 통과되었다면 실제 재고 확보를 위해 기존 DB 재고 로직이 수행된다.

시퀀스 다이어그램

image

Redis 기반 재고 및 부하 분산 흐름 정리

  1. Redis 재고 선점 (Traffic Filtering)
    요청이 들어오면 DB에 접근하기 전, Redis의 reserve 메서드를 통해 재고 확보를 먼저 시도합니다.
    Redis는 싱글 스레드 기반으로 원자적(Atomic) 연산을 수행하므로, 재고가 소진된 경우 DB 트랜잭션까지 진입하지 않고 즉시 요청을 거절합니다.
    이를 통해 불필요한 DB 커넥션 점유와 락 대기 시간을 획기적으로 감소시켰습니다.
  2. 멱등성 검증 (Idempotency Check)
    Redis 선점에 성공했더라도, 네트워크 지연이나 재시도 로직에 의해 이미 처리된 요청일 수 있습니다.
    DB 트랜잭션 내부에서 Winner 테이블을 조회하여 동일한 idempotencyKey로 처리된 내역이 있는지 확인합니다.
    이미 처리된 요청이라면 Redis 선점 내역을 롤백(Rollback)하고, 기존 처리 결과를 반환하여 데이터 일관성을 유지합니다.
  3. DB 트랜잭션 및 정합성 보장 (Consistency)
    Redis와 멱등성 검증을 통과한 유효한 요청에 대해서만 DB의 비관적 락(findByIdForUpdate)을 획득합니다.
    실제 재고 차감(decreaseStock)과 당첨자 생성(Winner), 로그 기록(BidInventoryLog)을 하나의 트랜잭션으로 묶어 최종적인 데이터 정합성을 보장합니다.
  4. 예외 처리 및 보상 트랜잭션 (Compensating Transaction)
    DB 트랜잭션 수행 중 예외가 발생하거나 비즈니스 로직(예: 판매 종료)에 의해 실패하는 경우, stockRedisService.rollback을 호출합니다.
    선점했던 Redis 재고를 다시 원복시켜 Redis와 DB 간의 재고 수량 불일치를 방지합니다.

기술적 선택 이유

Redis와 Lua를 활용한 첫 번째 이유는 높은 트래픽 환경에서 원자적으로 제어할 수 있기 때문입니다.

선착순 이벤트는 순간적으로 엄청난 트래픽이 몰리게 되는데 이를 감당하기 위해 디스크 기반의 MQ 보다는 인메모리 기반의 Redis가 적합하다고 판단했습니다. 또한 단순 재고 차감 로직을 위해 MQ의 컨슈머를 별도로 구현하는 것은 과하다고 생각했습니다.
대신 Lua Script를 활용하여 간단하게 원자적 연산을 수행하고자 했습니다.

두 번째 이유는 명확한 역할 분리를 통해 DB로 몰리는 부하를 구조적으로 분산할 수 있기 때문입니다.

Redis는 재고의 최종 상태를 관리하지 않고 수 많은 요청 중 일부만 선별하는 진입 제어 역할을 수행합니다.

즉, Redis는 높은 트래픽을 먼저 받아 여기서 통과된 요청만 DB로 전달하고, DB는 제한된 요청에 대해서만 최종 재고 검증하고 확정합니다.

그 외 변경된 내용

  • 스레드 풀 고갈로 인해 비동기 작업 예외가 발생하는 문제 해결
    • pageSize를 50으로 불러오고, 스레드풀의 스레드 개수를 60으로 설정
      - java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy() 정책을 추가하여 스레드 풀이 고갈되면 작업을 수행하던 스레드가 다음 작업을 동기적으로 실행하고, 이후 다시 스레드 풀에 여유가 생기면 메인 스레드는 비동기 스레에 작업을 위임하는 방향으로 수행됨
    • 배포를 위한 application-prod.yml 추가 (Bid, Order)

@yoo20370 yoo20370 self-assigned this Dec 23, 2025
@yawning5 yawning5 self-requested a review December 24, 2025 09:05
@yoo20370 yoo20370 merged commit daed741 into dev Dec 24, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants